package com.cbw.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 *映射器(包含了大量的路径与方法的对应关系)
 */
public class HandlerMapping {
    /**
     * 定义Map集合存放路径与映射对象一一对应，每次请求都会到map集合查询路径对应的方法
     */
    private static Map<String,MVCMapping>data=new HashMap();

    /**
     * 通过路径获取对应的映射对象(存放对应的请求方法和响应类型)
     * @param uri
     * @return
     */
    public static MVCMapping get(String uri){
        return data.get(uri); //即从map中通过键uri获取值MVCMapping映射对象
    }
    /**
     * 加载配置文件
     * @param is
     */
    public static void load(InputStream is){
        Properties ppt = new Properties();
        try {
            ppt.load(is);//将配置文件的输入流加载到properties对象中(将配置文件数据加载到该对象中)
        } catch (IOException e) {
            e.printStackTrace();
        }
        Collection<Object> values = ppt.values();//获取配置文件中描述的一个个类(即值)
        //下面进行反射处理，获取类，再获取该对象，再获取方法，将
        for (Object cla : values) { //遍历所有的类
            String className= (String) cla;
            try {
                Class c = Class.forName(className);//(加载配置文件中描述的每一个类)即获取类的class对象
                Object obj = c.getConstructor().newInstance();//获取这个类的对象
                Method[] methods = c.getMethods();//获取该类的所有公有方法
                for (Method method : methods) {
                    Annotation[] as = method.getAnnotations();//获取该类中每一个方法的所有注解
                    if (as!=null){ //该方法存在注解
                        for (Annotation annotation : as) {//遍历该方法中的注解
                            if (annotation instanceof ResponseBody){ //若注解是ResponseBody类型，表示此方法返回字符串给客户端
                                //将请求路径与映射对象MVCMapping封装到map中
                                MVCMapping mvcMapping=new MVCMapping(obj,method,ResponseType.TEXT);
                                System.out.println("映射对象:"+mvcMapping);
                                System.out.println("请求地址:"+((ResponseBody) annotation).value());
                                System.out.println("请求方法:"+mvcMapping.getMethod());
                                Object o=data.put(((ResponseBody) annotation).value(),mvcMapping);
                                if (o!=null){
                                    //存在重复的请求地址
                                    throw new RuntimeException("请求地址重复"+((ResponseBody) annotation).value());
                                }
                            }else if (annotation instanceof ResponseView){//若注解是ResponseView类型，表示此方法返回界面给客户端
                                //将请求路径与映射对象MVCMapping封装到map中
                                MVCMapping mvcMapping=new MVCMapping(obj,method,ResponseType.VIEW);
                                Object o=data.put(((ResponseView) annotation).value(),mvcMapping);
                                if (o!=null){
                                    //存在重复的请求地址
                                    throw new RuntimeException("请求地址重复"+((ResponseView) annotation).value());
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("映射地址池:");
    }

    /**
     *定义映射对象
     * 每一个映射对象封装了一个请求方法，用于处理请求
     */
    public static class MVCMapping{
        private Object obj; //对象
        private Method method;//请求对应的方法
        private ResponseType type;//方法返回的类型(枚举类型)

        public MVCMapping() {
        }

        public MVCMapping(Object obj, Method method, ResponseType type) {
            this.obj = obj;
            this.method = method;
            this.type = type;
        }

        public Object getObj() {
            return obj;
        }

        public void setObj(Object obj) {
            this.obj = obj;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public ResponseType getType() {
            return type;
        }

        public void setType(ResponseType type) {
            this.type = type;
        }

        @Override
        public String toString() {
            return "MVCMapping{" +
                    "obj=" + obj +
                    ", method=" + method +
                    ", type=" + type +
                    '}';
        }
    }
}
